package com.yc.sole.framework.utils;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.yc.sole.framework.exception.BaseException;
import com.yc.sole.framework.excel.ExcelFillCellMergeStrategy;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * excel工具类
 *
 * @author yizuomin
 * @date 2022/12/8 17:11
 **/
@Slf4j
public class EasyExcelUtil {

    /**
     * 导入
     *
     * @param file
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> List<T> importExcel(MultipartFile file, final Class<T> clazz) {
        if (file == null) {
            throw new BaseException("导入文件不能为空");
        }
        ExcelListener<T> listener = new ExcelListener<>();
        try {
            EasyExcel.read(file.getInputStream(), clazz, listener).sheet().doRead();
        } catch (IOException e) {
            throw new BaseException(e);
        }
        return listener.getDataList();
    }

    /**
     * 导出
     *
     * @param response
     * @param list
     * @param fileName
     * @throws IOException
     */
    public static void exportExcel(HttpServletResponse response, List<?> list, String fileName) {
        exportExcel(response, list, fileName, null);
    }

    /**
     * 导出
     *
     * @param response
     * @param list
     * @param fileName
     * @param sheetName
     * @throws IOException
     */
    public static void exportExcel(HttpServletResponse response, List<?> list, String fileName, String sheetName) {
        if (CharSequenceUtil.isEmpty(fileName)) {
            fileName = new Date().toString();
        }
        if (CharSequenceUtil.isEmpty(sheetName)) {
            sheetName = "Sheet1";
        }
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码
            String encodeFileName = URLEncoder.encode(fileName, "UTF-8").replace("\\+", "%20");
            if (!fileName.endsWith(".xlsx") || !fileName.endsWith(".xls")) {
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeFileName + ".xlsx");
            } else {
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeFileName);
            }
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置头字体
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 13);
            headWriteCellStyle.setWriteFont(headWriteFont);
            headWriteCellStyle.setShrinkToFit(true);
            //设置头居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            //内容策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
            // 这里需要设置不关闭流
            EasyExcelFactory.write(response.getOutputStream(), list.get(0).getClass()).autoCloseStream(Boolean.FALSE)
                    .registerWriteHandler(horizontalCellStyleStrategy).sheet(sheetName)
                    .doWrite(list);
        } catch (Exception e) {
            log.error("exception:{}", e.getMessage());
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, Object> map = new HashMap<>(3);
            map.put("code", 500);
            map.put("success", false);
            map.put("message", "下载文件失败" + e.getMessage());
            try {
                response.getWriter().println(JSONUtil.toJsonStr(map));
            } catch (IOException ex) {
                throw new BaseException(ex.getMessage());
            }
        }
    }


    /**
     * 导出
     *
     * @param response
     * @param list
     * @param fileName
     * @param sheetName
     * @throws IOException
     */
    public static void exportExcel(HttpServletResponse response, List<?> list, String fileName, String sheetName, int[] mergeColumnIndex, int mergeRowIndex) {
        if (CharSequenceUtil.isEmpty(fileName)) {
            fileName = new Date().toString();
        }
        if (CharSequenceUtil.isEmpty(sheetName)) {
            sheetName = "Sheet1";
        }
        try {
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码
            String encodeFileName = URLEncoder.encode(fileName, "UTF-8").replace("\\+", "%20");
            if (!fileName.endsWith(".xlsx") || !fileName.endsWith(".xls")) {
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeFileName + ".xlsx");
            } else {
                response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + encodeFileName);
            }
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置头字体
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 13);
            headWriteCellStyle.setWriteFont(headWriteFont);
            headWriteCellStyle.setShrinkToFit(true);
            //设置头居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            //内容策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            // 垂直居中
            contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
            // 内容自动换行
            contentWriteCellStyle.setWrapped(true);
            contentWriteCellStyle.setShrinkToFit(true);//设置文本收缩至合适
            ExcelFillCellMergeStrategy excelFillCellMergeStrategy = ExcelFillCellMergeStrategy.newInstance(mergeColumnIndex, mergeRowIndex);
            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
            // 这里需要设置不关闭流
            EasyExcelFactory.write(response.getOutputStream(), list.get(0).getClass()).autoCloseStream(Boolean.FALSE)
                    .registerWriteHandler(horizontalCellStyleStrategy).sheet(sheetName)
                    .registerWriteHandler(excelFillCellMergeStrategy)
                    .doWrite(list);
        } catch (Exception e) {
            log.error("exception:{}", e.getMessage());
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, Object> map = new HashMap<>(3);
            map.put("code", 500);
            map.put("success", false);
            map.put("message", "下载文件失败" + e.getMessage());
            try {
                response.getWriter().println(JSONUtil.toJsonStr(map));
            } catch (IOException ex) {
                throw new BaseException(ex.getMessage());
            }
        }
    }


    /**
     * 导入
     *
     * @param excel 上传的excel文件
     * @param clazz 要导入的实体类的class
     */
    public static <T> List<T> readerExcel(MultipartFile excel, Class<T> clazz) throws Exception {
        if (excel.isEmpty()) {
            throw new Exception("请选择excel文件");
        }
        String fileName = excel.getOriginalFilename();
        log.info("Excel文件解析：文件名 = " + fileName);
        if (fileName == null || (!fileName.toLowerCase().endsWith(".xls") && !fileName.toLowerCase().endsWith(".xlsx"))) {
            throw new Exception("文件格式错误");
        }
        try (InputStream fileStream = new BufferedInputStream(excel.getInputStream())) {
            ExcelListener<T> excelListener = new ExcelListener<>();
            EasyExcel.read(fileStream, clazz, excelListener)
                    .autoTrim(true)
                    .sheet()
                    .doRead();
            return excelListener.getDataList();
        } catch (Exception e) {
            log.error("导入失败, 请检查导入数据的准确性", e);
            throw new Exception("导入失败, 请检查导入数据的准确性");
        }
    }
}
